package jmine.selenium.services.validar;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.sf.json.JSON;
import net.sf.json.JSONArray;
import net.sf.json.JSONSerializer;

import org.apache.log4j.Logger;
import org.junit.Assert;

import com.thoughtworks.selenium.Selenium;

/**
 * Classe utilitaria para navegação no JSCookMenu em testes de selenium.
 * 
 * @author Rafael Volpato
 * @date Apr 15, 2012
 */
public final class JSCookMenuHelper {

    private static final int JSON_LIST_START_INDEX = 5;

    private static final Logger LOG = Logger.getLogger(JSCookMenuHelper.class);

    /**
     * Construtor
     */
    private JSCookMenuHelper() {
        super();
    }

    /**
     * Retorna o menu no formato de um mapa key: linkId, value: path
     * 
     * @param selenium {@link Selenium}
     * @return o menu no formato de um mapa key: linkId, value: path
     */
    public static Map<String, List<String>> getMenu(Selenium selenium) {
        String applicationMenu = selenium.getEval("applicationMenu");

        // Reformatar a string adicionando '"' (aspas)
        applicationMenu =
                applicationMenu.replaceAll(", ", "\", \"").replaceAll("\"\\[", "[\"").replaceAll("\\]\", ", "], ")
                        .replaceAll("[^\"]l\\]", "\"l]").replaceAll("\"nu\"l", "\"null\"").replaceAll("\\[\\[", "[[\"")
                        .replaceAll(", \"null\"", ", null").replaceAll("\"null\",", "null,");
        JSON json = JSONSerializer.toJSON(applicationMenu);
        if (!json.isArray()) {
            Assert.fail("Erro ao tentar obter os dados referentes ao menu");
            return null;
        } else {
            JSONArray jsonArray = (JSONArray) json;
            Map<String, List<String>> result = new HashMap<String, List<String>>();
            for (int i = 0; i < json.size(); i++) {
                result.putAll(menuFlatternRecursive(jsonArray.getJSONArray(i), new ArrayList<String>()));
            }
            return result;
        }
    }

    /**
     * Transforma o objeto json utilizado pelo JSCookMenu em um mapa.
     * 
     * @param json {@link JSONArray}
     * @param path path até esse ponto
     * @return o menu no formato de um mapa key: linkId, value: path
     */
    private static Map<String, List<String>> menuFlatternRecursive(JSONArray json, ArrayList<String> path) {
        String title = json.getString(1);
        String link = json.getString(2);

        ArrayList<String> newPath = new ArrayList<String>(path);
        newPath.add(title);
        if (title != null && !"null".equals(link)) {
            Map<String, List<String>> result = new HashMap<String, List<String>>();
            result.put(link.replaceAll("\\?wicket:bookmarkablePage=:", ""), newPath);
            return result;
        }

        Map<String, List<String>> result = new HashMap<String, List<String>>();
        for (int i = JSON_LIST_START_INDEX; i < json.size(); i++) {
            JSONArray jsonArray = json.getJSONArray(i);
            result.putAll(menuFlatternRecursive(jsonArray, newPath));
        }
        return result;
    }

    /**
     * Abre a página que esta no caminho informado.
     * 
     * @param selenium {@link Selenium}
     * @param path caminho para a página
     */
    public static void goTo(Selenium selenium, String... path) {
        String menuItemPath = "";
        for (int i = 0; i < path.length; i++) {
            menuItemPath = menuItemPath + path[i];

            if (i == 0) {
                LOG.debug("mouseOver " + "menu" + menuItemPath);
                selenium.mouseOver("menu" + menuItemPath);

            } else if (i == path.length - 1) {
                LOG.debug("click " + "//tr[@id = \"" + menuItemPath + "\"]/td/a[text() = \"" + path[i] + "\"]");
                selenium.click("//tr[@id = \"" + menuItemPath + "\"]/td/a[text() = \"" + path[i] + "\"]");
                selenium.waitForPageToLoad("30000");

            } else {
                LOG.debug("mouseOver " + menuItemPath);
                selenium.mouseOver(menuItemPath);
            }
            menuItemPath = menuItemPath + ".";
        }
    }

    /**
     * Retorna o caminho para a página informada.
     * 
     * @param selenium selenium
     * @param pageClass pageClass
     * @return o caminho para a página informada
     */
    public static List<String> getPathForWicketPage(Selenium selenium, Class<?> pageClass) {
        Map<String, List<String>> menu = getMenu(selenium);
        if (menu.containsKey(pageClass.getName())) {
            return menu.get(pageClass.getName());
        } else {
            Assert.fail("Página não encontrada no menu: " + pageClass.getName());
            return null;
        }
    }
}
